package com.pucong.gitee.database.backup.business.service.service;

import com.pucong.gitee.database.backup.business.service.cover.ServiceFileServiceBeanConvert;
import com.pucong.gitee.database.backup.business.service.mapper.ServiceFileMapper;
import com.pucong.gitee.database.backup.business.service.mapper.ServiceFileOperationHistoryMapper;
import com.pucong.gitee.database.backup.business.service.util.fileService.FileOperationService;
import com.pucong.gitee.database.backup.business.service.util.fileService.FileOperationServiceFactory;
import com.pucong.gitee.database.backup.business.sys.mapper.SysFileMapper;
import com.pucong.gitee.database.backup.business.sys.service.SysFileService;
import com.pucong.gitee.database.backup.common.entity.service.ServiceFile;
import com.pucong.gitee.database.backup.common.entity.service.ServiceFileOperationHistory;
import com.pucong.gitee.database.backup.common.entity.service.dto.*;
import com.pucong.gitee.database.backup.common.entity.service.vo.ServiceFileTreeVo;
import com.pucong.gitee.database.backup.common.entity.sys.SysFile;
import com.pucong.gitee.database.backup.common.entity.sys.UserJwt;
import com.pucong.gitee.database.backup.common.selfenum.FileServiceHistoryTypeEnum;
import com.pucong.gitee.database.backup.common.selfenum.ServiceFileType;
import com.pucong.gitee.database.backup.configuration.exception.BusinessException;
import com.pucong.gitee.database.backup.utils.UUID;
import com.pucong.gitee.database.backup.utils.UserRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class ServiceFileServiceImpl implements ServiceFileService {

    @Autowired
    private ServiceFileMapper serviceFileMapper;

    @Autowired
    private ServiceFileOperationHistoryMapper serviceFileOperationHistoryMapper;

    @Autowired
    private ServiceFileServiceBeanConvert serviceFileServiceBeanConvert;

    @Autowired
    private SysFileMapper sysFileMapper;

    @Autowired
    private SysFileService sysFileService;

    @Override
    public ServiceFile getFileServerById(String id) {
        ServiceFile serviceFile = serviceFileMapper.selectById(id);
        serviceFile.setPassword("");
        return serviceFile;
    }

    @Override
    public int insertFileServer(ServiceFileSaveDto dto) {
        ServiceFile serviceFile = serviceFileServiceBeanConvert.dto2do(dto);
        UserJwt loginUser = UserRequest.getLoginUser();
        String uuid = UUID.uuid();
        serviceFile.setUuid(uuid);
        serviceFile.setCreateBy(loginUser.getUuid());
        serviceFile.setCreateTime(new Date());
        serviceFileMapper.insert(serviceFile);
        return 1;
    }

    @Override
    public int updateFileServerById(String id, ServiceFileSaveDto dto) {
        ServiceFile serviceFileUpdate = new ServiceFile();
        serviceFileUpdate.setUuid(id);
        serviceFileUpdate.setServiceFileName(dto.getServiceFileName());
        serviceFileUpdate.setHost(dto.getHost());
        serviceFileUpdate.setPort(dto.getPort());
        serviceFileUpdate.setGroupName(dto.getGroupName());
        serviceFileUpdate.setUsername(dto.getUsername());
        serviceFileUpdate.setPassword(dto.getPassword());
        serviceFileUpdate.setServiceFileType(dto.getServiceFileType());
        serviceFileMapper.updateById(serviceFileUpdate);
        return 1;
    }

    @Override
    public List<ServiceFileTreeVo> getFileServerCatalogueById(String id, String cataloguePath) {
        final UserJwt loginUser = UserRequest.getLoginUser();
        ServiceFile serviceFile = serviceFileMapper.selectById(id);
        FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
        try {
            List<ServiceFileTreeVo> fileServerCatalogue = fileService.getFileServerCatalogue(cataloguePath);
            // 排序
            fileServerCatalogue.sort((o1, o2) -> {
                Boolean fileTrue1 = o1.getFileTrue();
                Boolean fileTrue2 = o2.getFileTrue();

                Boolean link1 = o1.getLink();
                Boolean link2 = o2.getLink();
                if (link1) {
                    fileTrue1 = false;
                }
                if (link2) {
                    fileTrue2 = false;
                }
                if ((fileTrue1 && !fileTrue2) || (!fileTrue1 && fileTrue2)) {
                    if (fileTrue1) {
                        return 1;
                    }
                    if (fileTrue2) {
                        return -1;
                    }
                }
                String fileName1 = o1.getFileName();
                String fileName2 = o2.getFileName();
                return fileName1.compareToIgnoreCase(fileName2);
            });
            insertLog(id, serviceFile.getServiceFileType(), FileServiceHistoryTypeEnum.查询, cataloguePath, loginUser.getUuid());
            return fileServerCatalogue;
        } catch (Exception e) {
            log.error("获取目录失败", e);
            throw new BusinessException(e.getMessage());
        } finally {
            fileService.close();
        }
    }

    @Override
    public Boolean uploadFile(String uuid, ServiceFileUploadDto dto) {
        final UserJwt loginUser = UserRequest.getLoginUser();
        SysFile sysFile = sysFileMapper.selectById(dto.getFileId());
        File file = new File(sysFile.getPath());
        // 获取文件名
        String fileNameOld = sysFile.getFileNameOld();
        // 上传
        ServiceFile serviceFile = serviceFileMapper.selectById(uuid);
        FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
        boolean b = false;
        try (InputStream inputStream = new FileInputStream(file)) {
            String path = dto.getPath();
            b = fileService.uploadFile(inputStream, path, fileNameOld);
        } catch (IOException e) {
            log.error("上传文件失败", e);
            throw new BusinessException("上传文件失败");
        } finally {
            fileService.close();
        }
        insertLog(uuid, serviceFile.getServiceFileType(), FileServiceHistoryTypeEnum.上传文件,dto.getPath() + ":"+ sysFile.toString(), loginUser.getUuid());
        // 删除缓存文件
        sysFileService.deleteFileById(dto.getFileId());
        return b;
    }

    @Override
    public Boolean uploadFileList(String uuid, ServiceFilesUploadDto dto) {
        UserJwt loginUser = UserRequest.getLoginUser();
        List<String> fileIds = dto.getFileIds();
        List<SysFile> sysFiles = sysFileMapper.selectBatchIds(fileIds);
        ServiceFile serviceFile = serviceFileMapper.selectById(uuid);
        FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
        try {
            for (SysFile sysFile : sysFiles) {
                File file = new File(sysFile.getPath());
                // 获取文件名
                String fileNameOld = sysFile.getFileNameOld();
                // 上传
                InputStream inputStream = new FileInputStream(file);
                String path = dto.getPath();
                boolean b = fileService.uploadFile(inputStream, path, fileNameOld);
            }
        } catch (IOException e) {
            log.error("上传文件失败", e);
            throw new BusinessException("上传文件失败");
        } finally {
            fileService.close();
        }
        // 删除临时文件
        sysFileService.deleteFileByIdList(fileIds);
        insertLog(uuid, serviceFile.getServiceFileType(), FileServiceHistoryTypeEnum.上传文件, dto.toString() + sysFiles.toString(), loginUser.getUuid());
        return true;
    }

    @Override
    public Boolean deleteFile(String uuid, String path) {
        final UserJwt loginUser = UserRequest.getLoginUser();
        ServiceFile serviceFile = serviceFileMapper.selectById(uuid);
        FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
        boolean b = fileService.deleteFile(path);
        fileService.close();
        insertLog(uuid, serviceFile.getServiceFileType(), FileServiceHistoryTypeEnum.删除文件, path, loginUser.getUuid());
        return b;
    }

    @Override
    public void downLoadFileByPath(String uuid, String path, HttpServletResponse response) {
        final UserJwt loginUser = UserRequest.getLoginUser();
        int idx = path.lastIndexOf("/");
        String fileName = path.substring(idx + 1, path.length());
        response.reset();
        //首先设置响应的内容格式是force-download，那么你一旦点击下载按钮就会自动下载文件了
        response.setContentType("application/force-download");
        //通过设置头信息给文件命名，也即是，在前端，文件流被接受完还原成原文件的时候会以你传递的文件名来命名
        try {
            // 设置文件名 支持中文 采用中文文件名需要在此处转码
            fileName = new String(fileName.getBytes("GBK"), "ISO_8859_1");
            response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
        } catch (UnsupportedEncodingException e) {
            log.error("不支持文件返回设置编码", e);
        }
        ServiceFile serviceFile = serviceFileMapper.selectById(uuid);
        FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
        try (final ServletOutputStream outputStream = response.getOutputStream()) {
            fileService.downloadFile(outputStream, path);
        } catch (IOException e) {
            log.error("下载文件失败", e);
            throw new BusinessException("下载文件失败");
        } finally {
            fileService.close();
        }
        insertLog(uuid, serviceFile.getServiceFileType(), FileServiceHistoryTypeEnum.下载文件, path, loginUser.getUuid());
    }

    @Override
    public void lookFileByPath(String uuid, String path, HttpServletResponse response) {
        final UserJwt loginUser = UserRequest.getLoginUser();
        ServiceFile serviceFile = serviceFileMapper.selectById(uuid);
        FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
        try (final ServletOutputStream outputStream = response.getOutputStream()) {
            fileService.downloadFile(outputStream, path);
        } catch (IOException e) {
            log.error("预览文件失败", e);
            throw new BusinessException("预览文件失败");
        } finally {
            fileService.close();
        }
        insertLog(uuid, serviceFile.getServiceFileType(), FileServiceHistoryTypeEnum.下载文件, path, loginUser.getUuid());
    }

    @Override
    public Boolean connectTest(ServiceFileConnectTestDto dto) {
        final UserJwt loginUser = UserRequest.getLoginUser();
        ServiceFile serviceFile = serviceFileServiceBeanConvert.dto2do(dto);
        try {
            FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
            Boolean success = fileService.connectTest();
            fileService.close();
            return success;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public Boolean addCatalogue(String uuid, ServiceFileAddDirDto dto) {
        final UserJwt loginUser = UserRequest.getLoginUser();
        if (".".equals(dto.getAddName()) || "..".equals(dto.getAddName())) {
            throw new BusinessException("非法目录");
        }
        ServiceFile serviceFile = serviceFileMapper.selectById(uuid);
        FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
        try {
            fileService.addCatalogue(dto.getFilePath(), dto.getAddName());
        } catch (Exception e) {
            log.error("创建文件目录失败", e);
            throw new BusinessException("创建文件目录失败：" + e.getMessage());
        } finally {
            fileService.close();
        }
        insertLog(uuid, serviceFile.getServiceFileType(), FileServiceHistoryTypeEnum.添加文件夹, dto.toString(), loginUser.getUuid());
        return true;
    }

    @Override
    public Boolean deleteDir(String uuid, String filePath) {
        UserJwt loginUser = UserRequest.getLoginUser();
        ServiceFile serviceFile = serviceFileMapper.selectById(uuid);
        FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
        boolean b = fileService.deleteCatalogue(filePath);
        fileService.close();
        insertLog(uuid, serviceFile.getServiceFileType(), FileServiceHistoryTypeEnum.删除文件夹, filePath, loginUser.getUuid());
        return b;
    }

    @Override
    public Boolean rename(String uuid, ServiceFileRenameDto dto) {
        UserJwt loginUser = UserRequest.getLoginUser();
        ServiceFile serviceFile = serviceFileMapper.selectById(uuid);
        FileOperationService fileService = FileOperationServiceFactory.getFileService(loginUser.getUuid(), serviceFile);
        boolean b = fileService.rename(dto.getFilePath(),dto.getOldName(),dto.getNewName());
        fileService.close();
        insertLog(uuid, serviceFile.getServiceFileType(), FileServiceHistoryTypeEnum.修改文件名, dto.toString(), loginUser.getUuid());
        return b;
    }

    /**
     * 添加操作日志
     * @param fileListUuid
     * @param serviceFileType
     * @param operationType
     * @param operationContent
     * @param createBy
     */
    private void insertLog(String fileListUuid, ServiceFileType serviceFileType, FileServiceHistoryTypeEnum operationType, String operationContent, String createBy) {
        ServiceFileOperationHistory insert = new ServiceFileOperationHistory();
        insert.setUuid(UUID.uuid());
        insert.setOperationType(operationType);
        insert.setFileListUuid(fileListUuid);
        insert.setFileServiceType(serviceFileType);
        insert.setOperationContent(operationContent);
        insert.setCreateBy(createBy);
        insert.setCreateTime(new Date());
        serviceFileOperationHistoryMapper.insert(insert);
    }
}
